<?php
/**
 *       _____
 *      /  \  \      _       _    _____________   ___     ___ '  TM
 *     / /\ \  \    | |\    | |\ /_____   _____\ | - |   | - |
 *    / /  \ \  \   | | |   | | ||____/| |\____| | - |___| - |
 *   / /   /\ \  \  | | |   | | |    | | | |     | -  ___  - |
 *  / /   /  \ \  \ | |_|___| | |    | |_| |     | - |   | - |
 * / /___/    \ \__\|________ |/     |/___\|     |___|   |___|
 *________________________________________________________________________
 * 
 * classe du systeme de Cache General, Classe mère pour les classes Cache_html, Cache_Http, Cache_Image, Cache_Function, Cache_Sql...
 *
 *
 * PHP version 5
 *
 * LICENSE: GNU General Public License v3
 *
 * @package    Cache
 * @subpackage Cores
 * @author     Poly Charly <CharlyPoly@gmail.fr>
 * @copyright  2009 Authentic Development Group
 * @license    GNU General Public License v3
 * @version    Cache System Version 0.2
 * @todo       create childrens class
 *
 **/
class cache {
    /*
     * @var string
     */
	private $cache         =   NULL;
    /*
     * @var string
     */
	private $filePath;
    /*
     * @var int
     */
	private $lifeTime;
     /*
     * @var string
     */
	private $fileExt;
    /*
     * @var string
     */
    private $lock           =   true;
    /*
     * @var boolean
     */
    private $WriteControl   =   false;
    /*
     * @var boolean
     */
    private $ReadControl    =   false;
    /*
     * @var string
     */
    public  $cacheDir;
    /*
     * @var string
     */
    public  $cacheDB;
    /*
     * @var string
     */
    public  $cacheMode      =   "file"; //file or db
    /*
     * @type static
     * @var  string
     */
    static $FILE            =   "file";
    /*
     * @type static
     * @var  string
     */
    static $DB              =   "db";
    /*
     * @var boolean
     */
    private $fpOpen         =   false;


    /*
     * @example $cache = new Cache("cache/", array('lifeTime'=>3600, 'extension'=>'.myCache'));
     * @example if ($content = $cache->get($file)) echo $content;
     * @example if ($cache->save("hello world !")) echo "cache saved !";
     */
	function __construct ($ID, $args) {
		$this->filePath     = $this->cacheDir  = $args['cacheDir'];
        $this->fileExt      = (isset($args['extension'])) ? $args['extension']  : '.cache';
		$this->filePath    .= (!is_null($args['key'])) ? md5($ID).$this->fileExt.'.php' : md5($ID.$args['key']).$this->fileExt.'.php';
		$this->lifeTime     = (isset($args['lifeTime']) && is_int($args['lifeTime'])) ? $args['lifeTime'] : NULL;
        $this->lock         = (isset($args['lock']) && is_bool($args['lock'])) ? $args['lock'] : TRUE;
        $this->ReadControl = (isset($args['ReadControl']) && is_bool($args['ReadControl'])) ? $args['ReadControl'] : FALSE;
        $this->WriteControl = (isset($args['WriteControl']) && is_bool($args['WriteControl'])) ? $args['WriteControl'] : FALSE;
	}

	private function isCached() {
		if (file_exists($this->filePath)  === FALSE) return false;
		if (filemtime($this->filePath) < (time() - $this->lifeTime)) return false;
		return true;
	}

	public function get() {
		if (!is_null($this->cache)) return $this->cache;
		if (!$this->isCached()) return false;
        switch($mode) {
            case "file":
                return $this->getFromFile();
                break;
            case "db":
                return $this->getFromDB();
                break;
            default:
                Error::getInstance(E_WARNING ,'Cache Mode must be "file" or "db" ( or )', __FILE__, __LINE__);
                break;
        }
	}

	public function save($content=NULL, $link=FALSE) {
		if (is_null($this->cache) && !is_null($content)) $this->cache = $content;
        else return false;
		switch($this->cacheMode) {
            case "file":
                $this->saveFile($content);
                break;
            case "db":
                if ($link !== FALSE) {
                    $this->saveDB($content, $link);
                } else {
                    Error::getInstance(E_ERROR ,'Save with DB mode need a DBObject link !', __FILE__, __LINE__);
                }
                break;
            default:
                Error::getInstance(E_WARNING ,'Cache Mode must be "file" or "db" ( or )', __FILE__, __LINE__);
                break;
        }
	}

	public function saveAs($url, $content=NULL, $fetch = TRUE) {
        if ($this->cacheMode != "file") return false;
		if (is_null($this->cache) && !is_null($content)) $this->cache = $content;
        else return false;
		if ($this->lock) $tempnam = tempnam($this->cacheDir, "CACHE");
        $writed = file_put_contents( ($lock) ? $tempnam : $url  , $content , ($append) ? FILE_APPEND : '' );
        if (($this->lock) && ($writed !== FALSE)) rename($tempnam ,$url);
        @unlink($tempnam);
        return ($this->WriteControl) ? true :($writed == strlen($this->cache));
	}

    public function delete() {
        switch($mode) {
            case "file":
                return $this->unlinkFromFile();
                break;
            case "db":
                return $this->unlinkFromDB();
                break;
            default:
                Error::getInstance(E_WARNING ,'Cache Mode must be "file" or "db" ( or )', __FILE__, __LINE__);
                break;
        }
    }

    public function deleteAll($cacheDir=NULL) {
        switch($mode) {
            case "file":
                if ($dr = opendir((is_null($cacheDir)) ? $this->cacheDir : $cacheDir)) {
                    while (($file = readdir($dr)) !== false) {
                        if ($file != "." && $file != "..") {
                            $this->_unlink($file);
                        }
                    }
                    closedir($dr);
                }
                break;
            case "db":
                //action at Server, Delete all records
                break;
            default:
                Error::getInstance(E_WARNING ,'Cache Mode must be "file" or "db" ( or )', __FILE__, __LINE__);
                break;
        }
    }

    public function setDB($db) {
        $this->cacheDB = (string) $db;
    }

    public function setMode($mode) {
        switch($mode) {
            case "file":
                $this->cacheMode = "file";
                break;
            case "db":
                $this->cacheMode = "db";
                break;
            default:
                Error::getInstance(E_WARNING ,'Cache Mode must be "file" or "db" ( or )', __FILE__, __LINE__);
                break;
        }
    }

    private function unlinkFromFile() {
        return ($this->fpOpen) ? false : @unlink($this->filePath);
    }

    private function unlinkFromDB() {
        // Action at Server
    }

    private function saveFile ($content) {
        if ($this->lock) $tempnam = tempnam($this->cacheDir, "CACHE");
        $writed = file_put_contents( ($lock) ? $tempnam : $this->filePath  , $content , ($append) ? FILE_APPEND : '' );
        if (($this->lock) && ($writed !== FALSE)) rename($tempnam ,$this->filePath);
        @unlink($tempnam);
        return ($this->WriteControl) ? true :($writed == strlen($this->cache));
    }

    private function saveDB ($content, $link) {
        // Action at Server
    }

    private function getFromFile() {
        $handle = fopen($this->filePath, "r");
        if ($handle) $this->fpOpen = true;//fp ressource stats for unlink function fix bug
        $contents = fread($handle, filesize($this->filePath));
        $return = $this->cache =  $contents;
        if ($this->ReadControl) {
            $return = (strlen($contents) == filesize($this->filePath)) ? $this->cache : false;
        }
        if (fclose($handle)) $this->fpOpen = false; //fp ressource stats for unlink function fix bug

		return $return;
    }

    private function getFromDB() {
        // Action at Server
    }
}
?>
